﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Xml.Linq;
using System.Configuration;
using System.IO;

namespace SQLDiag.UI
{
    public partial class FormMainNew : Form
    {
        // Counters for the number of checked child nodes -- added by shen 12/17/2010
        private int[] perfNodeCheckedCount = new int[1000];
        private int[] profilerNodeCheckedCount = new int[1000];
        private String curFileName = "SQLDiag.xml"; // current configure filename -- added by Shen 12/17/2010 
        private string sqlDiagPath = "";
        private string outputFolder = "";
        private string configFilePath = "";
        private Process p = null;

        public FormMainNew()
        {
            InitializeComponent();
        }

        #region Tabpage Navigation
        private void btnNextWelcome_Click(object sender, EventArgs e)
        {
            //go to configuration
            this.tabControlMain.SelectTab(1);
        }

        private void btnConfigPrev_Click(object sender, EventArgs e)
        {
            //go to welcome
            this.tabControlMain.SelectTab(0);
        }

        private void btnNext_Click(object sender, EventArgs e)
        {
            //go to perfmon
            this.tabControlMain.SelectTab(2);
        }

        private void btnPerfmonPrev_Click(object sender, EventArgs e)
        {
            //go back to configuraiton
            this.tabControlMain.SelectTab(1);
        }

        private void btnPerfmonNext_Click(object sender, EventArgs e)
        {
            //go to profiler
            this.tabControlMain.SelectTab(3);
        }

        private void btnProfilerPrev_Click(object sender, EventArgs e)
        {
            //go back to perfmon
            this.tabControlMain.SelectTab(2);
        }

        private void btnProfilerNext_Click(object sender, EventArgs e)
        {
            //go to summary
            this.tabControlMain.SelectTab(4);
        }

        private void btnSummaryPrev_Click(object sender, EventArgs e)
        {
            this.tabControlMain.SelectTab(3);
        }

        #endregion

        private void btnSummaryRun_Click(object sender, EventArgs e)
        {
            //run SQLDiag.exe
            try
            {
                String tempFileName = "";
                if (configFilePath == "")
                    //save the current configuration to a temp file
                    tempFileName = outputFolder + @"\SQLDiag" + Guid.NewGuid().ToString() + ".xml";
                else
                    tempFileName = configFilePath;
                this.FileSave(tempFileName);

                p = new Process();

                ProcessStartInfo psi = new ProcessStartInfo();
                psi.FileName = sqlDiagPath;

                string sOutputFolder = outputFolder;
                //DirectoryInfo di = new DirectoryInfo(sOutputFolder);
                //sOutputFolder = di.CreateSubdirectory(Guid.NewGuid().ToString()).FullName;

                psi.Arguments = string.Format("/i \"{0}\" /o \"{1}\"", tempFileName, sOutputFolder);
                psi.UseShellExecute = true;
                psi.RedirectStandardOutput = false;
                psi.CreateNoWindow = false;

                p.EnableRaisingEvents = true;
                p.StartInfo = psi;

                p.Start();

                this.Visible = false;
                p.WaitForExit();
                this.Visible = true;
                this.tabControlMain.SelectTab(0);
                MessageBox.Show("SQLDiag.exe finished with Exit code: " + p.ExitCode, "Status", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                this.Visible = true;
                this.toolStripStatusLabelMain.Text = ex.Message;
            }
        }

        private void FileSave(string fileName)
        {
            try
            {
                if (System.IO.File.Exists(fileName))
                    if (MessageBox.Show("Configure file already exits! Do you want to overwrite it?","Alert!", MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.Cancel)
                        return;

                //save result back to SQLDiag.xml
                XDocument doc = XDocument.Load("SQLDiag.xml");

                // save machine name - added by Shen 12/12/2010 
                if (tbMachineName.Text == "")
                {
                    MessageBox.Show("Invalid Machine Name!");
                    return;
                }
                else
                    doc.Descendants("Machine").First().SetAttributeValue("name", tbMachineName.Text);

                // save instance name - added by Shen 12/12/2010 
                if (tbInstanceName.Text == "")
                {
                    MessageBox.Show("Invalid Instance Name!");
                    return;
                }
                else
                    doc.Descendants("Instance").First().SetAttributeValue("name", tbInstanceName.Text);

                //save blocking collector's checkbox - added by Shen 12/12/2010 
                if (cbBlocking.Checked)
                    doc.Descendants("BlockingCollector").First().SetAttributeValue("enabled", "true");

                if (cbPerfmon.Checked)
                {
                    //first enable perfmon collector -- added by Shen 12/12/2010
                    doc.Descendants("PerfmonCollector").First().SetAttributeValue("enabled", "true");

                    //save Perfmon counters
                    //get the root node and perfmon objects nodes below it
                    TreeNodeCollection tnc = this.tvPerfmon.Nodes[0].Nodes;

                    //for each perfmon object, set perfmon counters
                    foreach (TreeNode tn in tnc)
                    {
                        TreeNodeCollection tncPerfCounters = tn.Nodes;

                        //find the perf object and set "enabled" attribute accondingly -- added by shen 12/17/2010
                        IEnumerable<XElement> perfObj = from po in doc.Descendants("PerfmonObject")
                                                        where po.Attributes("name").First().Value == tn.Text
                                                        select po;
                        perfObj.First().SetAttributeValue("enabled", tn.Checked);

                        //find the perfmon counter and set the "enabled" attribute to be the value of treenode checked property
                        foreach (TreeNode tn1 in tncPerfCounters)
                        {
                            IEnumerable<XElement> perfCounter = from pc in doc.Descendants("PerfmonCounter")
                                                                where pc.Attributes("name").First().Value == tn1.Text && pc.Parent.Attributes("name").First().Value == tn.Text
                                                                select pc;

                            perfCounter.First().SetAttributeValue("enabled", tn1.Checked);
                        }
                    }
                }

                if (cbProfiler.Checked)
                {
                    //first enable profiler collector- - added by Shen 12/12/2010
                    doc.Descendants("ProfilerCollector").First().SetAttributeValue("enabled", "true");

                    //save profiler events
                    //get the root node and all profiler event types nodes below it
                    //events/eventType/event
                    TreeNodeCollection tncProfilerEventTypes = this.tvProfiler.Nodes[0].Nodes;

                    //for each event type, set event "enabled" property based on checkbox value
                    foreach (TreeNode tn in tncProfilerEventTypes)
                    {
                        TreeNodeCollection tncEvents = tn.Nodes;

                        //find the event type and set "enabled" attribute accondingly -- added by shen 12/17/2010
                        IEnumerable<XElement> profilerEvtType = from evt in doc.Descendants("EventType")
                                                                where evt.Attributes("name").First().Value == tn.Text
                                                                select evt;
                        profilerEvtType.First().SetAttributeValue("enabled", tn.Checked);

                        //find the event and set the "enabled" attribute to be the value of treenode checked property
                        foreach (TreeNode tn1 in tncEvents)
                        {
                            IEnumerable<XElement> profilerEvent = from ev in doc.Descendants("Event")
                                                                  where ev.Attributes("name").First().Value == tn1.Text && ev.Parent.Attributes("name").First().Value == tn.Text
                                                                  select ev;

                            profilerEvent.First().SetAttributeValue("enabled", tn1.Checked);
                        }
                    }
                }

                doc.Save(fileName);

                // change the message -- modified by shen 12/12/2010
                MessageBox.Show(fileName + " is saved.", "SQLDiag.XML", MessageBoxButtons.OK);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK);
            }
        }

        private void FormMainNew_Load(object sender, EventArgs e)
        {
            if(sqlDiagPath == "")
                sqlDiagPath = ConfigurationManager.AppSettings["SQLDiagPath"].ToString();
            this.tbSQLDiagPath.Text = sqlDiagPath;

            if(outputFolder == "")
                outputFolder = ConfigurationManager.AppSettings["OutputFolder"].ToString();
            this.tbOutputFolder.Text = outputFolder;
            
            //ConfigFilePath
            //configFilePath = ConfigurationManager.AppSettings["ConfigFilePath"].ToString();
            //this.tbConfigFilePath.Text = configFilePath;

            this.KeyPreview = true;

            LoadConfigFile();
        }

        private void LoadConfigFile()
        {
            for (int i = 0; i < 1000; i++)
            {
                perfNodeCheckedCount[i] = 0;
                profilerNodeCheckedCount[i] = 0;
            }

            //load default SQLDiag.xml
            if (configFilePath != "")
                curFileName = configFilePath;

            XDocument doc = XDocument.Load(curFileName);

            //preset values according to opened file -- added by Shen 12/17/2010
            var blockElm = from bl in doc.Descendants("BlockingCollector")
                           select bl;
            cbBlocking.Checked = (blockElm.First().Attributes("enabled").First().Value == "true");

            var perfMonElm = from pf in doc.Descendants("PerfmonCollector")
                             select pf;
            cbPerfmon.Checked = (perfMonElm.First().Attributes("enabled").First().Value == "true");
            tvPerfmon.Enabled = cbPerfmon.Checked;

            var profilerElm = from profiler in doc.Descendants("ProfilerCollector")
                              select profiler;
            cbProfiler.Checked = (profilerElm.First().Attributes("enabled").First().Value == "true");
            tvProfiler.Enabled = cbProfiler.Checked;

            var machineNameElm = from mn in doc.Descendants("Machine")
                                 select mn;
            tbMachineName.Text = machineNameElm.First().Attributes("name").First().Value;

            var instanceNameElm = from inst in doc.Descendants("Instance")
                                  select inst;
            tbInstanceName.Text = instanceNameElm.First().Attributes("name").First().Value;

            LoadPerfmon(doc);

            LoadProfiler(doc);
        }

        private void LoadProfiler(XDocument doc)
        {
            this.tvProfiler.Nodes.Clear();

            //add root node
            TreeNode tnRoot = new TreeNode("Profiler");
            this.tvProfiler.Nodes.Add(tnRoot);

            //load profiler events
            var profilerEventTypes = from pet in doc.Descendants("EventType")
                                     select pet;

            foreach (var item in profilerEventTypes)
            {
                TreeNode tn = new TreeNode(item.Attributes("name").First().Value);

                //initialize the checked values -- Added by Shen 12/12/2010
                if (item.Attributes("enabled").Count() != 0)
                    if (item.Attributes("enabled").First().Value == "true")
                    {
                        tn.BackColor = System.Drawing.SystemColors.ControlDark;
                        tn.Checked = true;
                    }

                tnRoot.Nodes.Add(tn);

                //load profiler events under event type
                var profilerEvents = from pe in item.Descendants("Event")
                                     select pe;

                foreach (var itemPe in profilerEvents)
                {
                    TreeNode tnPe = new TreeNode(itemPe.Attributes("name").First().Value);

                    //initialize the checked values -- Added by Shen 12/12/2010
                    if (itemPe.Attributes("enabled").Count() != 0)
                        if (itemPe.Attributes("enabled").First().Value == "true")
                        {
                            if (!tn.Checked)
                                tn.BackColor = System.Drawing.SystemColors.ControlDark;

                            profilerNodeCheckedCount[tn.Index]++;
                            tnPe.Checked = true;
                        }
                    tn.Nodes.Add(tnPe);
                }
            }

            tnRoot.Expand();
        }

        private void LoadPerfmon(XDocument doc)
        {
            this.tvPerfmon.Nodes.Clear();

            //add root node
            TreeNode tnRoot = new TreeNode("Perfmon Objects");
            this.tvPerfmon.Nodes.Add(tnRoot);

            //load perfmon objects
            var perfObjects = from po in doc.Descendants("PerfmonObject")
                              select po;

            foreach (var item in perfObjects)
            {
                TreeNode tn = new TreeNode(item.Attributes("name").First().Value);

                //initialize the checked values -- Added by Shen 12/12/2010
                if (item.Attributes("enabled").Count() != 0)
                    if (item.Attributes("enabled").First().Value == "true")
                    {
                        tn.BackColor = System.Drawing.SystemColors.ControlDark;
                        tn.Checked = true;
                    }

                tnRoot.Nodes.Add(tn);

                //load perfmon counters under the object
                var perfmonCounters = from pc in item.Descendants("PerfmonCounter")
                                      select pc;

                foreach (var itemPc in perfmonCounters)
                {
                    TreeNode tnPc = new TreeNode(itemPc.Attributes("name").First().Value);

                    //initialize the checked values -- Added by Shen 12/12/2010
                    if (itemPc.Attributes("enabled").Count() != 0)
                        if (itemPc.Attributes("enabled").First().Value == "true")
                        {
                            if (!tn.Checked)
                                tn.BackColor = System.Drawing.SystemColors.ControlDark;

                            perfNodeCheckedCount[tn.Index]++;
                            tnPc.Checked = true;
                        }

                    tn.Nodes.Add(tnPc);
                }
            }

            tnRoot.Expand();
        }

        private void btnSQLDiagEXEPathBrowse_Click(object sender, EventArgs e)
        {
            if (DialogResult.OK == this.openFileDialogSQLDiag.ShowDialog())
            {
                this.tbSQLDiagPath.Text = this.openFileDialogSQLDiag.FileName;
                sqlDiagPath = this.tbSQLDiagPath.Text.Trim();
                ConfigurationManager.AppSettings["SQLDiagPath"] = sqlDiagPath;
            }
        }

        private void btnOutputFolderBrowse_Click(object sender, EventArgs e)
        {
            if (DialogResult.OK == this.folderBrowserDialogMain.ShowDialog())
            {
                this.tbOutputFolder.Text = this.folderBrowserDialogMain.SelectedPath;
                outputFolder = tbOutputFolder.Text;
            }
        }

        private void btnConfigFilePathBrowse_Click(object sender, EventArgs e)
        {
            if (DialogResult.OK == this.openFileDialogConfigure.ShowDialog())
            {
                this.tbConfigFilePath.Text = this.openFileDialogConfigure.FileName;

                if (configFilePath == tbConfigFilePath.Text)
                    return;

                this.configFilePath = this.tbConfigFilePath.Text;

                if (System.IO.File.Exists(configFilePath))
                    LoadConfigFile();
            }
        }

        private void tvProfiler_AfterCheck(object sender, TreeViewEventArgs e)
        {
            ToggleCheckbox(e);
            highlightParent(e, profilerNodeCheckedCount);
        }

        private void tvPerfmon_AfterCheck(object sender, TreeViewEventArgs e)
        {
            ToggleCheckbox(e);
            highlightParent(e, perfNodeCheckedCount);
        }

        private static void ToggleCheckbox(TreeViewEventArgs e)
        {
            TreeNodeCollection tna = e.Node.Nodes;
            bool isChecked = e.Node.Checked;

            foreach (TreeNode tn in tna)
            {
                tn.Checked = isChecked;
            }
        }

        void highlightParent(TreeViewEventArgs e, int[] nodeCheckedCount)
        {
            if (e.Node.Level == 2) // If this a leaf node, highlight the parent -- Added by Shen 12/17/2010
            {
                if (e.Node.Checked)
                {
                    e.Node.Parent.BackColor = System.Drawing.SystemColors.ControlDark;
                    nodeCheckedCount[e.Node.Parent.Index]++;
                }
                else
                {
                    if (--nodeCheckedCount[e.Node.Parent.Index] <= 0)
                        e.Node.Parent.BackColor = System.Drawing.SystemColors.Control;
                }
            }

            if (e.Node.Level == 1) // For second level node, highlight itself -- added by shen 12/17/2010
            {
                if (e.Node.Checked)
                    e.Node.BackColor = System.Drawing.SystemColors.ControlDark;
                else
                    e.Node.BackColor = System.Drawing.SystemColors.Control;
            }
        }

        private void cbPerfmon_CheckedChanged(object sender, EventArgs e)
        {
            this.tvPerfmon.Enabled = this.cbPerfmon.Checked;
        }

        private void cbProfiler_CheckedChanged(object sender, EventArgs e)
        {
            tvProfiler.Enabled = cbProfiler.Checked;
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            this.FileSave(configFilePath);
        }

        private void btnPerfmonSave_Click(object sender, EventArgs e)
        {
            this.FileSave(configFilePath);
        }

        private void btnProfilerSave_Click(object sender, EventArgs e)
        {
            this.FileSave(configFilePath);
        }

        private void btnSumSave_Click(object sender, EventArgs e)
        {
            this.FileSave(configFilePath);
        }

        private void tbConfigFilePath_TextChanged(object sender, EventArgs e)
        {
            if (configFilePath == tbConfigFilePath.Text)
                return;

            this.configFilePath = this.tbConfigFilePath.Text;

            if (System.IO.File.Exists(configFilePath))
                LoadConfigFile();
        }

        private void tbOutputFolder_TextChanged(object sender, EventArgs e)
        {
            outputFolder = tbOutputFolder.Text;
        }

        private void tpSummary_Enter(object sender, EventArgs e)
        {
            refreshSummary();
        }

        private void refreshSummary()
        {
            rtbSummary.Text =
                "\n\tSQLDiag Path:\t\t" + sqlDiagPath + "\n\n" +
                "\tOutput Folder:\t\t" + outputFolder + "\n\n" +
                "\tConfiguration File Path:\t" + configFilePath + "\n\n" +
                "\tMachine Name:\t\t" + tbMachineName.Text + "\n\n" +
                "\tInstance Name:\t\t" + tbInstanceName.Text + "\n\n" +
                "\tBlocking Status Enabled:\t" + cbBlocking.Checked + "\n\n" +
                "\tPerfmon Enabled:\t" + cbPerfmon.Checked + "\n\n" +
                "\tProfiler Enabled:\t\t" + cbProfiler.Checked + "\n\n";
        }
    }//class
}//namespace
